﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="GestureEngine.cs" company="arvystate.net">
//   arvystate.net
// </copyright>
// <summary>
//   Base class that handles tracking
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace PresentationAid.Lib.GestureEngines
{
    using NLog;

    using PresentationAid.Lib.Enums;
    using PresentationAid.Lib.GestureEngines.GestureSettings;

    /// <summary>
    /// Base class that handles tracking
    /// </summary>
    public abstract class GestureEngine
    {
        #region Static Fields

        /// <summary>
        /// The logger.
        /// </summary>
        private static readonly Logger Logger = LogManager.GetCurrentClassLogger();

        #endregion

        #region Fields

        /// <summary>
        /// Id of the skeleton that is tracked if it is not controllable
        /// </summary>
        private int trackedId;

        #endregion

        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="GestureEngine"/> class. 
        /// Sets default values for gesture engine
        /// </summary>
        protected GestureEngine()
        {
            this.ControlGesture = GestureCommand.JoinedHands;

            Logger.Trace("Init: GestureEngine");
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets or sets the Control gesture
        /// </summary>
        public GestureCommand ControlGesture { get; set; }

        /// <summary>
        /// Gets Id of the currently tracked Skeleton
        /// </summary>
        public int ControlId
        {
            get
            {
                return this.trackedId;
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether engine is in slideshow mode
        /// </summary>
        public virtual bool IsInSlideshow { get; protected set; }

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets engine settings window
        /// </summary>
        protected GestureEngineSettingsWindow EngineSettings { get; set; }

        #endregion

        #region Public Methods and Operators

        /// <summary>
        /// Executes gesture
        /// </summary>
        /// <param name="gesture">
        /// Gesture to execute
        /// </param>
        /// <param name="trackingId">
        /// TrackingId that executed the gesture
        /// </param>
        /// <returns>
        /// True on success <see cref="bool"/>.
        /// </returns>
        public bool ExecuteGesture(GestureCommand gesture, int trackingId)
        {
            Logger.Info(
                "Method: ExecuteGesture - Gesture: {0}, TrackingId: {1}, ControlGesture: {2}", 
                gesture.ToString(), 
                trackingId, 
                this.ControlGesture.ToString());

            // Checking if tracking ID has permission to control engine
            if (this.ControlGesture != GestureCommand.None)
            {
                // Override gesture command if it is control gesture
                if (gesture == this.ControlGesture)
                {
                    Logger.Debug("MethodDetail: ExecuteGesture - ControlGesture");

                    this.trackedId = trackingId;
                }
                else if (this.trackedId == trackingId)
                {
                    // Otherwise check for permission
                    Logger.Debug("MethodDetail: ExecuteGesture - GestureByTrackingId");

                    this.ExecuteSpecificGesture(gesture);
                }

                Logger.Trace("MethodDetail: ExecuteGesture - GestureIgnored");

                return false;
            }

            return this.ExecuteSpecificGesture(gesture);
        }

        /// <summary>
        /// Abstract method returns configured mapping as a string
        /// </summary>
        /// <returns>
        /// Configured mapping as a string <see cref="string"/>.
        /// </returns>
        public abstract string GetMapping();

        /// <summary>
        /// Abstract method returns slideshow command mapped to gesture
        /// </summary>
        /// <param name="gesture">
        /// The gesture.
        /// </param>
        /// <returns>
        /// SlideShowCommand mapped to gesture <see cref="SlideShowCommand"/>.
        /// </returns>
        public abstract SlideShowCommand GetSlideShowCommand(GestureCommand gesture);

        /// <summary>
        /// Returns true if skeleton's tracking ID is in control of presentation
        /// </summary>
        /// <param name="trackingId">
        /// Tracking Id of the skeleton to check
        /// </param>
        /// <returns>
        /// True if it is in control <see cref="bool"/>.
        /// </returns>
        public bool IsInControl(int trackingId)
        {
            return trackingId == this.trackedId || this.ControlGesture == GestureCommand.None;
        }

        /// <summary>
        /// Parse mapping abstract method
        /// </summary>
        /// <param name="map">
        /// Mapping as a string
        /// </param>
        /// <returns>
        /// True on success <see cref="bool"/>.
        /// </returns>
        public abstract bool ParseMapping(string map = null);

        /// <summary>
        /// Sets control of the gesture engine to provided tracking Id
        /// </summary>
        /// <param name="trackingId">
        /// Tracking Id of the control skeleton
        /// </param>
        public void SetControl(int trackingId)
        {
            Logger.Debug("Method: SetControl - TrackingId: {0}", trackingId);

            this.trackedId = trackingId;
        }

        /// <summary>
        /// The set default mapping.
        /// </summary>
        public virtual void SetDefaultMapping()
        {
            Logger.Trace("Method: SetDefaultMapping - Base");
            this.ControlGesture = GestureCommand.JoinedHands;
        }

        /// <summary>
        /// Opens settings dialog
        /// </summary>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        public bool ShowSettings()
        {
            Logger.Trace("Method: ShowSettings");

            if (this.EngineSettings != null)
            {
                this.EngineSettings.CreateSettings();
                this.EngineSettings.LoadSettings();
                this.EngineSettings.Show();

                return true;
            }

            return false;
        }

        #endregion

        #region Methods

        /// <summary>
        /// The execute specific gesture.
        /// </summary>
        /// <param name="gesture">
        /// The gesture.
        /// </param>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        protected abstract bool ExecuteSpecificGesture(GestureCommand gesture);

        #endregion
    }
}